package ai.fabu.dataplatform.utils;

import ai.fabu.dataplatform.PathProto;
import ai.fabu.dataplatform.bean.help.Position;
import com.google.protobuf.InvalidProtocolBufferException;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.FileUtils;
import roadstar.localization.LocalizationOuterClass;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Slf4j
public class FileUtil {

    // read file in binary mode
    public static byte[] readByteFile(@NotBlank String path) throws IOException{
        try{
            return Files.readAllBytes(Paths.get(path));
        } catch (IOException e) {
            log.error("file: {} read fail", path);
            e.printStackTrace();
            throw e;
        }
    }


    // read file in string mode
    public static String readFileByPath(@NotBlank String path){
        File file = new File(path);
        if(!file.exists() || !file.isFile())  return null;
        try{
            StringBuilder builder = new StringBuilder();
            List<String> stringList = Files.readAllLines(Paths.get(path));
            stringList.forEach(string->builder.append(string).append("\n"));
            return builder.toString();
        } catch (IOException e) {
            log.error("file: {} read fail", path);
            e.printStackTrace();
        }
        return null;
    }

    // read ros localization file in binary mode and convert binary data into list of gps which has been filtered every other interval
    public static List<Position> readLocalizationFileByPath(@NotBlank String path, @Min(1) int interval){
        List<Position> points = new ArrayList<>();
        try{
            PathProto.Path localization = PathProto.Path.parseFrom(new FileInputStream(path));
            List<PathProto.Path.Point> pointsList = localization.getPointsList();
            for(int i = 0; i + 1 < pointsList.size(); i += interval)
                points.add(new Position(pointsList.get(i).getUtmX(), pointsList.get(i).getUtmY()));
            if(!pointsList.isEmpty())  points.add(new Position(pointsList.get(pointsList.size()-1).getUtmX(), pointsList.get(pointsList.size()-1).getUtmY()));
        } catch (FileNotFoundException e) {
            log.error("file: {} not found", path);
            e.printStackTrace();
        } catch (IOException e) {
            log.error("file: {} read fail", path);
            e.printStackTrace();
        }
        return points;
    }
    // convert binary data into list of gps which has been filtered every other interval
    public static List<Position> readLocalizationDataByBytes(@NotNull byte[] bytes, @Min(1) int interval){
        List<Position> points = new ArrayList<>();
        try{
            PathProto.Path localization = PathProto.Path.parseFrom(bytes);
            List<PathProto.Path.Point> pointsList = localization.getPointsList();
            for(int i = 0; i + 1 < pointsList.size(); i += interval)
                points.add(new Position(pointsList.get(i).getUtmX(), pointsList.get(i).getUtmY()));
            if(!pointsList.isEmpty())  points.add(new Position(pointsList.get(pointsList.size()-1).getUtmX(), pointsList.get(pointsList.size()-1).getUtmY()));
        } catch (InvalidProtocolBufferException e) {
            log.error("readLocalizationDataByBytes: invalid proto bytes");
            e.printStackTrace();
        }
        return points;
    }


    // delete directory recursively
    public static void deleteDirectoryRecursively(@NotNull File directory) throws IOException, IllegalArgumentException {
        FileUtils.deleteDirectory(directory);
    }

    // create file recursively , if it exists, delete it and create a new one
    public static boolean createFileRecursively(File file){
        try{
            File parentFile = file.getParentFile();
            if(!parentFile.isDirectory()){
                if(!parentFile.mkdirs()){
                    log.error("createFileRecursively: create directory: {} recursively fail", parentFile.getAbsolutePath());
                }
            }
            if(file.isFile()){
                log.warn("createFileRecursively: file: {} exists but delete it", file.getAbsolutePath());
                if(!file.delete()){
                    log.warn("createFileRecursively: file: {} delete fail", file.getAbsolutePath());
                    return false;
                }
            }
            if(!file.createNewFile()){
                log.error("createFileRecursively: create file: {} fail", file.getAbsolutePath());
                return false;
            }
        } catch (IOException e) {
            log.error("createFileRecursively: create file: {} fail", file.getAbsolutePath());
            e.printStackTrace();
            return false;
        }
        return true;
    }

    // convert raw binary data into list of gps which has been filtered every other interval
    public static List<Position> readLocalizationBinFileByBytes(@NotNull byte[] bytes, @Min(1) int interval){
        log.info("readLocalizationBinFileByBytes: interval: {}", interval);
        int i = 0;
        List<Position> pointList = new ArrayList<>();
        int number = 0;
        while(i + 8 < bytes.length){
            i += 4;
            ByteBuffer byteBuffer = ByteBuffer.wrap(bytes, i, 4);
            int size = byteBuffer.order(ByteOrder.LITTLE_ENDIAN).getInt();
            i += 4;
            if(number % interval == 0) {
                try{
                    LocalizationOuterClass.Localization localization = LocalizationOuterClass.Localization.parseFrom(Arrays.copyOfRange(bytes, i, i + size));
                    pointList.add(new Position(localization.getUtmX(), localization.getUtmY()));
                } catch (InvalidProtocolBufferException e) {
                    log.error("readLocalizationBinFileByBytes: invalid proto bytes");
                    e.printStackTrace();
                    return pointList;
                }
            }
            ++number;
            i += size;
        }
        return pointList;
    }

    // read raw binary file in binary mode and convert it into list of gps which has been filtered every other interval
    public static List<Position> readLocalizationBinFileByPath(@NotBlank String path, @Min(1) int interval){
        byte[] bytes;
        try {
            bytes = readByteFile(path);
        } catch (IOException e){
            return new ArrayList<>();
        }
        return readLocalizationBinFileByBytes(bytes, interval);
    }

//    public static double[] loadTxtFileForGPS(String path) {
//        InputStream is;
//        double[] gps = new double[2];
//        try {
//            is = new FileInputStream(path);
//            String line; // 用来保存每行读取的内容
//            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
//            try {
//                // 读取第一行
//                line = reader.readLine();
//                // 如果 line 为空说明读完了
//                while (line != null) {
//                    // 将读到的内容添加到 buffer 中
//                    if (line.contains("utm_x")) {
//                        String utmX = line.split(":")[1].trim();
//                        double x = Double.parseDouble(utmX);
//                        gps[0] = x;
//                    }
//                    if (line.contains("utm_y")) {
//                        String utmX = line.split(":")[1].trim();
//                        double y = Double.parseDouble(utmX);
//                        gps[1] = y;
//                    }
//                    line = reader.readLine();
//                }
//                reader.close();
//                is.close();
//                return gps;
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        } catch (FileNotFoundException e) {
//            e.printStackTrace();
//        }
//        return gps;
//    }

//    public static byte[] loadBinFile(String binPath) {
////        binPath = "/home/qinpeifa/data/hangzhou/truck01/20180601/1219/dump.bin";
//        File file = new File(binPath);
//        InputStream inputStream;
//        if (file.exists()) {
//            try {
//                inputStream = new FileInputStream(file);
//                int availByteLen = inputStream.available();
//                log.info("字节数" + availByteLen);
//                byte[] buffer = new byte[availByteLen];
//                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
//                int len = -1;
//                while ((len = inputStream.read(buffer)) != -1) {
//                    //todo 多余的步骤 直接输出buffer即可
//                    byteArrayOutputStream.write(buffer, 0, len);
//                }
//                byteArrayOutputStream.close();
//                inputStream.close();
//                byte[] byteArray = byteArrayOutputStream.toByteArray();
//                log.info("字节数" + availByteLen);
//                return byteArray;
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        } else {
//            log.error("bin文件不存在");
//            return null;
//        }
//        return null;
//    }
}
